<template>
  <div
      class="slider-container"
      :class="[orientation, { disabled }]"
      @mouseenter="$emit('mouseenter')"
      @mouseleave="$emit('mouseleave')"
  >
    <div
        class="slider-track"
        ref="trackRef"
        :style="trackStyle"
        @mousedown="handleTrackClick"
    >
      <div class="track-fill" :style="trackFillStyle"></div>

      <div
          class="slider-thumb"
          :style="thumbStyle"
          tabindex="0"
          @mousedown="startDragging"
          @keydown="handleKeydown"
          @focus="showTooltipTemp"
          @blur="hideTooltipTemp"
      >
        <div v-if="showTooltip" class="thumb-tooltip" :class="{ visible: isTooltipVisible }">
          {{ currentValue }}
        </div>
      </div>
    </div>

    <div v-if="hasMarks" class="slider-marks">
      <div
          v-for="(mark, value) in marks"
          :key="value"
          class="mark"
          :style="getMarkPosition(value)"
      >
        <span class="mark-label">{{ mark }}</span>
        <span v-if="dots" class="mark-dot"></span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue';

const props = defineProps({
  value: { type: Number, default: 0 },
  min: { type: Number, default: 0 },
  max: { type: Number, default: 100 },
  step: { type: Number, default: 1 },
  orientation: {
    type: String,
    default: 'horizontal',
    validator: val => ['horizontal', 'vertical'].includes(val)
  },
  disabled: { type: Boolean, default: false },
  showTooltip: { type: Boolean, default: true },
  color: { type: String, default: '#1890ff' },
  marks: { type: Object, default: () => ({}) },
  dots: { type: Boolean, default: false }
});

const emit = defineEmits(['update:value', 'change', 'input', 'mouseenter', 'mouseleave']);

const trackRef = ref(null);
const isDragging = ref(false);
const isTooltipVisible = ref(false);
const currentValue = ref(props.value);
const containerRect = ref(null);

// 计算属性
const trackStyle = computed(() => ({
  cursor: props.disabled ? 'not-allowed' : 'pointer',
  [props.orientation === 'horizontal' ? 'height' : 'width']: '4px'
}));

const trackFillStyle = computed(() => {
  const percentage = ((currentValue.value - props.min) / (props.max - props.min)) * 100;
  return {
    backgroundColor: props.color,
    [props.orientation === 'horizontal' ? 'width' : 'height']: `${percentage}%`
  };
});

const thumbStyle = computed(() => ({
  backgroundColor: props.color,
  [props.orientation === 'horizontal' ? 'left' : 'bottom']:
      `${((currentValue.value - props.min) / (props.max - props.min)) * 100}%`,
  cursor: props.disabled ? 'not-allowed' : 'grab'
}));

const hasMarks = computed(() => Object.keys(props.marks).length > 0 || props.dots);

// 方法
const getMarkPosition = (value) => {
  const position = ((value - props.min) / (props.max - props.min)) * 100;
  return { [props.orientation === 'horizontal' ? 'left' : 'bottom']: `${position}%` };
};

const updateValue = (newValue) => {
  newValue = Math.max(props.min, Math.min(props.max, newValue));
  newValue = Math.round(newValue / props.step) * props.step;

  if (newValue !== currentValue.value) {
    currentValue.value = newValue;
    emit('update:value', newValue);
    emit('input', newValue);
  }
};

const handleTrackClick = (e) => {
  if (props.disabled) return;
  const rect = trackRef.value.getBoundingClientRect();
  const newValue = props.orientation === 'horizontal'
      ? props.min + (e.clientX - rect.left) / rect.width * (props.max - props.min)
      : props.min + (rect.bottom - e.clientY) / rect.height * (props.max - props.min);

  updateValue(newValue);
  emit('change', newValue);
};

const startDragging = (e) => {
  if (props.disabled) return;
  isDragging.value = true;
  document.addEventListener('mousemove', handleDragging);
  document.addEventListener('mouseup', stopDragging);
  isTooltipVisible.value = true;
};

const handleDragging = (e) => {
  if (!isDragging.value) return;
  const rect = trackRef.value.getBoundingClientRect();
  const newValue = props.orientation === 'horizontal'
      ? props.min + (e.clientX - rect.left) / rect.width * (props.max - props.min)
      : props.min + (rect.bottom - e.clientY) / rect.height * (props.max - props.min);

  updateValue(newValue);
};

const stopDragging = () => {
  isDragging.value = false;
  document.removeEventListener('mousemove', handleDragging);
  document.removeEventListener('mouseup', stopDragging);
  isTooltipVisible.value = false;
  emit('change', currentValue.value);
};

const handleKeydown = (e) => {
  if (props.disabled) return;
  const stepMap = {
    ArrowLeft: -props.step,
    ArrowRight: props.step,
    ArrowDown: -props.step,
    ArrowUp: props.step
  };

  if (stepMap[e.key]) {
    e.preventDefault();
    updateValue(currentValue.value + stepMap[e.key]);
    emit('change', currentValue.value);
  }
};

const showTooltipTemp = () => {
  if (!props.showTooltip) return;
  isTooltipVisible.value = true;
};

const hideTooltipTemp = () => {
  if (!props.showTooltip) return;
  isTooltipVisible.value = false;
};

// 监听props变化
watch(() => props.value, (val) => {
  currentValue.value = val;
});
</script>

<style scoped>
.slider-container {
  position: relative;
  padding: 16px;
  &.horizontal {
    width: 100%;
    height: 32px;
  }
  &.vertical {
    height: 300px;
    width: 32px;
  }
  &.disabled {
    opacity: 0.6;
  }
}

.slider-track {
  position: relative;
  background: #eee;
  border-radius: 4px;
}

.slider-container.horizontal .slider-track {
  width: 100%;
  top: 50%;
  transform: translateY(-50%);
}

.slider-container.vertical .slider-track {
  height: 100%;
  left: 50%;
  transform: translateX(-50%);
}

.track-fill {
  position: absolute;
  border-radius: 4px;
  transition: width 0.2s, height 0.2s;
}

.horizontal .track-fill {
  height: 100%;
  left: 0;
  top: 0;
}

.vertical .track-fill {
  width: 100%;
  bottom: 0;
  left: 0;
}

.slider-thumb {
  position: absolute;
  width: 16px;
  height: 16px;
  background: #fff;
  border: 2px solid;
  border-radius: 50%;
  transition: all 0.2s;
}

.horizontal .slider-thumb {
  top: 50%;
  transform: translate(-50%, -50%);
}

.vertical .slider-thumb {
  left: 50%;
  transform: translate(-50%, 50%);
}

.thumb-tooltip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0,0,0,0.8);
  color: white;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  opacity: 0;
  transition: opacity 0.2s;
  &.visible {
    opacity: 1;
  }
}

.slider-marks {
  position: absolute;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.mark {
  position: absolute;
  transform: translate(-50%, 0);
  &.vertical {
    transform: translate(0, 50%);
  }
}

.mark-label {
  font-size: 12px;
  color: #666;
  white-space: nowrap;
}

.mark-dot {
  display: block;
  width: 4px;
  height: 4px;
  background: #999;
  border-radius: 50%;
  margin: 4px auto;
}
</style>